/*******************************************************************************
 * Copyright (c) 2002 - 2006 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package initial;

import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;



import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.examples.properties.WalaExamplesProperties;
import com.ibm.wala.ide.ui.SWTTreeViewer;
import com.ibm.wala.ide.ui.ViewIRAction;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.CallGraphStats;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.properties.WalaProperties;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.config.AnalysisScopeReader;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.graph.GraphIntegrity;
import com.ibm.wala.util.graph.InferGraphRoots;
import com.ibm.wala.util.io.CommandLine;
import com.ibm.wala.util.io.FileProvider;
import com.ibm.wala.util.io.FileUtil;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.StringStuff;

/**
 * 
 * This application is a WALA client: it invokes an SWT TreeViewer to visualize
 * a Call Graph
 * 
 * @author sfink
 */
public class FindMethodCall {

  private final static boolean CHECK_GRAPH = false;

  /**
   * Usage: SWTCallGraph -appJar [jar file name]
   * 
   * The "jar file name" should be something like
   * "c:/temp/testdata/java_cup.jar"
   * 
   * If it's a directory, then we'll try to find all jar files under that
   * directory.
   * 
   * @param args
   * @throws WalaException
   */
  public static void main(String[] args) throws WalaException {
    Properties p = CommandLine.parse(args);
    validateCommandLine(p);
    run(p, args[3]);
  }

  public static boolean isDirectory(String appJar) {
	    return (new File(appJar).isDirectory());
  }
  
  public static void validateCommandLine(Properties p) {
	    if (p.get("appJar") == null) {
	      throw new UnsupportedOperationException("expected command-line to include -appJar");
	    }
  }
  
  public static String findJarFiles(String[] directories) throws WalaException {
	    Collection<String> result = HashSetFactory.make();
	    for (int i = 0; i < directories.length; i++) {
	      for (Iterator<File> it = FileUtil.listFiles(directories[i], ".*\\.jar", true).iterator(); it.hasNext();) {
	        File f = (File) it.next();
	        result.add(f.getAbsolutePath());
	      }
	    }
	    return composeString(result);
  }
  
  private static String composeString(Collection<String> s) {
	    StringBuffer result = new StringBuffer();
	    Iterator<String> it = s.iterator();
	    for (int i = 0; i < s.size() - 1; i++) {
	      result.append(it.next());
	      result.append(';');
	    }
	    if (it.hasNext()) {
	      result.append(it.next());
	    }
	    return result.toString();
  }  
  /**
   * @param p
   *            should contain at least the following properties:
   *            <ul>
   *            <li>appJar should be something like
   *            "c:/temp/testdata/java_cup.jar"
   *            <li>algorithm (optional) can be one of:
   *            <ul>
   *            <li> "ZERO_CFA" (default value)
   *            <li> "RTA"
   *            </ul>
   *            </ul>
   * 
   * @throws WalaException
   */
  public static void run(Properties p, String methodSig) throws WalaException {

    try {
      String appJar = p.getProperty("appJar");
      if (isDirectory(appJar)) {
        appJar = findJarFiles(new String[] { appJar });// mutiple jar files here!!
      }

      String exclusionFile = p.getProperty("exclusions");

      AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, exclusionFile != null ? new File(exclusionFile)
          : FileProvider.getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS));

      ClassHierarchy cha = ClassHierarchy.make(scope);

      //Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha);
      ClassLoaderReference clr = scope.getApplicationLoader();
      final Atom mainMethod = Atom.findOrCreateAsciiAtom("onCreate");
      final HashSet<Entrypoint> result = HashSetFactory.make();
      for (IClass klass : cha) {
        if (klass.getClassLoader().getReference().equals(clr)) {
          MethodReference mainRef = MethodReference.findOrCreate(klass.getReference(), mainMethod, Descriptor
              .findOrCreateUTF8("(Landroid/os/Bundle;)V"));
          IMethod m = klass.getMethod(mainRef.getSelector());
          if (m != null) {
            result.add(new DefaultEntrypoint(m, cha));
          }
        }
      }
    
      Iterable<Entrypoint> entrypoints =  new Iterable<Entrypoint>() {
        public Iterator<Entrypoint> iterator() {
          return result.iterator();
        }
      };
      
      
      AnalysisOptions options = new AnalysisOptions(scope, entrypoints);

      // //
      // build the call graph
      // //
      com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope, null,
          null);
      CallGraph cg = builder.makeCallGraph(options,null);

      System.out.println(CallGraphStats.getStats(cg));

      if (CHECK_GRAPH) {
        GraphIntegrity.check(cg);
      }
      
      
      MethodReference mr = StringStuff.makeMethodReference(methodSig);
      Set<CGNode> nodeSet = cg.getNodes(mr);
      CGNode node;
      CallSiteReference ref;
      for(Iterator<CGNode> i = nodeSet.iterator(); i.hasNext();){
    	  node = i.next();
    	  
    	  IMethod m = node.getMethod();
    	  System.out.println("method signature "+m.getSignature());
    	  System.out.println("method LineNumber "+m.getLineNumber(0));
    	  System.out.println("method LineNumber "+m.getLineNumber(1));
    	  System.out.println("method Descriptor "+m.getDescriptor());
    	  
    	  for(Iterator<CallSiteReference> c = node.iterateCallSites(); c.hasNext();){
    		  ref = c.next();
    		  System.out.println("ref: "+ref.toString());
    	  }
    	  
    	  
      }
     /* Properties wp = null;
      try {
        wp = WalaProperties.loadProperties();
        wp.putAll(WalaExamplesProperties.loadProperties());
      } catch (WalaException e) {
        e.printStackTrace();
        Assertions.UNREACHABLE();
      }
      String psFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFWalaIR.PDF_FILE;
      String dotFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFTypeHierarchy.DOT_FILE;
      String dotExe = wp.getProperty(WalaExamplesProperties.DOT_EXE);
      String gvExe = wp.getProperty(WalaExamplesProperties.PDFVIEW_EXE);

      // create and run the viewer
      final SWTTreeViewer v = new SWTTreeViewer();
      v.setGraphInput(cg);
      v.setRootsInput(InferGraphRoots.inferRoots(cg));
      v.getPopUpActions().add(new ViewIRAction(v, cg, psFile, dotFile, dotExe, gvExe));
      v.run();
      return v.getApplicationWindow();*/

    } catch (Exception e) {
      e.printStackTrace();
      /*return null;*/
    }
  }
}
